#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"

#include "esp_log.h"
#include "mqtt_client.h"
#include "mqtt_handler.h"

#include "led_ctrl.h"

static const char *TAG = "mqtt_handler";
esp_mqtt_client_handle_t g_mqtt_client;      //mqtt客户端



static void log_error_if_nonzero(const char * message, int error_code)
{
    if (error_code != 0) {
        ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
    }
}

//设置LED 点亮
static esp_err_t leds_set_on_status(const char *p_topic,int topic_len,const char *p_data,int data_len)
{
    ESP_LOGI(TAG, ">>> topic = %.*s , data = %.*s >>>",topic_len, p_topic, data_len, p_data);
    ESP_LOGI(TAG, ">>> leds_set_on_status >>>");

    led_set_onoff(0);

    return ESP_OK;
}

//设置LED 熄灭
static esp_err_t leds_set_off_status(const char *p_topic,int topic_len,const char *p_data,int data_len)
{
    ESP_LOGI(TAG, ">>> topic = %.*s , data = %.*s >>>",topic_len, p_topic, data_len, p_data);
    ESP_LOGI(TAG, ">>> leds_set_off_status >>>");

    led_set_onoff(1);

    return ESP_OK;
}

//设置LED 逐渐点亮
static esp_err_t leds_fade_up(const char *p_topic,int topic_len,const char *p_data,int data_len)
{
    ESP_LOGI(TAG, ">>> topic = %.*s , data = %.*s >>>",topic_len, p_topic, data_len, p_data);
    ESP_LOGI(TAG, ">>> leds_fade_up >>>");

    led_fade_process(0);

    return ESP_OK;
}

//设置LED 逐渐熄灭
static esp_err_t leds_fade_down(const char *p_topic,int topic_len,const char *p_data,int data_len)
{
    ESP_LOGI(TAG, ">>> topic = %.*s , data = %.*s >>>",topic_len, p_topic, data_len, p_data);
    ESP_LOGI(TAG, ">>> leds_fade_up >>>");

    led_fade_process(1);

    return ESP_OK;
}

//mqtt消息处理列表
static mqtt_msg_handler_t mqtt_msg_handler[] = 
{
    {
        .topic = "/topic/led_status",
        .data = "led_on",
        .mqtt_msg_handler = leds_set_on_status,
    },

    {
        .topic = "/topic/led_status",
        .data = "led_off",
        .mqtt_msg_handler = leds_set_off_status,
    },

    {
        .topic = "/topic/led_status",
        .data = "led_fade_up",
        .mqtt_msg_handler = leds_fade_up,
    },

    {
        .topic = "/topic/led_status",
        .data = "led_fade_down",
        .mqtt_msg_handler = leds_fade_down,
    },
};

//mqtt消息处理函数，在这里通过轮询列表来分发处理命令
static void mqtt_message_handler(char* topic,int topic_len, char* p_data,int data_len)
{
    char _topic[32];
    char _data[32];

    int i = -1;

    memset(_topic,0x00,sizeof(_topic));memset(_data,0x00,sizeof(_data));
    strncpy(_topic,topic,topic_len);strncpy(_data,p_data,data_len);

    //ESP_LOGI(TAG, ">>> _topic = %s , topic_len = %d , _data = %s , data_len = %d >>>", _topic, topic_len, p_data, data_len);

    for (i = 0; i < (sizeof(mqtt_msg_handler)/sizeof(mqtt_msg_handler_t)); i++) 
    {
        if (!strcasecmp(_topic, mqtt_msg_handler[i].topic) && !strcasecmp(_data, mqtt_msg_handler[i].data))   //在mqtt消息列表里面，轮询topic和data
        {        
            mqtt_msg_handler[i].mqtt_msg_handler(_topic, topic_len, _data, data_len);   //使用列表里面的处理函数

            break;
        }
    }

    if ((sizeof(mqtt_msg_handler)/sizeof(mqtt_msg_handler_t)) == i)    //如果在列表里面找不到对应的topic和data
    {
       ESP_LOGI(TAG, ">>> mqtt_msg_not_found >>>");
    }
}

static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;

    switch (event->event_id) 
    {
        case MQTT_EVENT_CONNECTED:   //mqtt已连接
            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");

            msg_id = esp_mqtt_client_subscribe(client, (const char*)LED_STATUS_TOPIC, 0);   //订阅主题 /topic/led_status
            ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

            break;
        case MQTT_EVENT_DISCONNECTED:   //mqtt已断开
            ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
            break;

        case MQTT_EVENT_SUBSCRIBED:   //mqtt收到订阅事件
            ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
            
            break;
        case MQTT_EVENT_UNSUBSCRIBED:   //取消订阅事件
            ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_PUBLISHED:    //mqtt发布事件
            ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_DATA:
            ESP_LOGI(TAG, "MQTT_EVENT_DATA");

            //ESP_LOGI(TAG, ">>> _topic = %s , topic_len = %d , _data = %s , data_len = %d >>>", event->topic, event->topic_len, event->data, event->data_len);

            mqtt_message_handler(event->topic, event->topic_len, event->data, event->data_len);

            break;
        case MQTT_EVENT_ERROR:
            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
            if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) 
            {
                log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
                log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
                log_error_if_nonzero("captured as transport's socket errno",  event->error_handle->esp_transport_sock_errno);
                ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
            }
            break;
        default:
            ESP_LOGI(TAG, "Other event id:%d", event->event_id);
            break;
    }
    return ESP_OK;
}

//mqtt事件处理函数
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) 
{
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
    mqtt_event_handler_cb(event_data);   //mqtt事件处理函数
}

static void mqtt_app_start(void)
{
    //mqtt的配置信息，broker的地址
    esp_mqtt_client_config_t mqtt_cfg = {
        .uri = CONFIG_BROKER_URL,
    };

    g_mqtt_client = esp_mqtt_client_init(&mqtt_cfg);   //初始化mqtt客户端
    esp_mqtt_client_register_event(g_mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, g_mqtt_client);   //注册mqtt的事件回调函数
    esp_mqtt_client_start(g_mqtt_client);  //启动mqtt客户端
}

void mqtt_handler_init(void)
{
    //配置打印信息
    esp_log_level_set("*", ESP_LOG_INFO);
    esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
    esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
    esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
    esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
    esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
    esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);

    ESP_ERROR_CHECK(nvs_flash_init());    //初始化nvs flash
    ESP_ERROR_CHECK(esp_netif_init());    //初始化wifi
    ESP_ERROR_CHECK(esp_event_loop_create_default());   //设置默认事件

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());      //连接互联网

    mqtt_app_start();    //启动mqtt app
}

//发布mqtt消息，供外部模块调用
int mqtt_publish_message(const char* p_topic,const char* p_data,int len)
{
    int msg_id = -1;

    msg_id = esp_mqtt_client_publish(g_mqtt_client, p_topic, p_data, len, 0, 0);  //发布主题          
    //ESP_LOGI(TAG, ">>> mqtt_publish_message successful, msg_id=%d >>>", msg_id);

    return msg_id;
}
